package database

import (
	"context"
	"dustbe/util"
	"errors"
	"fmt"
	"strings"

	"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

func checkComment(text string) error {
	if len(text) == 0 {
		return errors.New("不能发布空评论！")
	}
	return nil
}

func GetPublisherNameByCommentId(commentId int64) (string, error) {
	var userName string
	m1 := "match (comment:BlogComment)<-[:Publish]-(user:DustUser)"
	w1 := fmt.Sprintf("where id(comment)=%d", commentId)
	r := "return comment, user;"
	cypher := m1 + " " + w1 + " " + r
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return userName, err
	}

	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("user")
		user := n.(neo4j.Node)
		userName = user.Props["name"].(string)
	}

	return userName, nil
}

// atId 为 -1代表不需要at人
func PublishComment(blogSeq, publisherId, atId, createTime int, text string) (int64, error) {
	text = strings.TrimSpace(text)
	var commentId int64

	if len(text) > 200 {
		return commentId, errors.New("发布的评论长度太长了！")
	}

	err := checkComment(text)
	if err != nil {
		return commentId, err
	}

	text, _ = util.AddDoubleQuote(text)
	m1 := fmt.Sprintf("match (blog:Blog{seq:%d})", blogSeq)
	m2 := fmt.Sprintf("match (user:DustUser) where id(user)=%d", publisherId)
	c1 := fmt.Sprintf("create (comment:BlogComment{createTime:%d,text:%s})", createTime, text)
	c2 := "create (blog)-[rc:Contain]->(comment)"
	c3 := "create (user)-[rp:Publish]->(comment)"
	r  := "return blog,user,comment,rc,rp;"

	m3 := ""
	c4 := ""

	if atId > 0 {
		m3 = fmt.Sprintf("match (atUser:DustUser) where id(atUser)=%d", atId)
		c4 = "create (comment)-[ra:At]->(atUser)"
		r = "return blog,user,comment,atUser,rc,rp;"
	}

	cypher := m1 + " " + m2 + " " + m3 + " " + c1 + " " + c2 + " " + c3 + " " + c4 + " "  + r
	
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return commentId, err
	}

	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("comment")
		comment := n.(neo4j.Node)
		commentId = comment.Id
	}
	return commentId, nil
}

func DeleteComment(commentId int) error {
	cypher := fmt.Sprintf("match (n:BlogComment) where id(n)=%d detach delete n", commentId)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())
	_, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return err
	}
	return nil
}	


func ModifyComment(commentId int, text string) error {
	text = strings.TrimSpace(text)

	err := checkComment(text)
	if err != nil {
		return err
	}

	text, _ = util.AddDoubleQuote(text)
	cypher := fmt.Sprintf("match (n:BlogComment) where id(n)=%d set n.text=%s", commentId, text)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())
	_, err = session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return err
	}

	return nil
}

type CommentTuple struct {
	CommentNode *neo4j.Node
	PublisherNode *neo4j.Node
	AtNode *neo4j.Node
}

func GetCommentsByBlogSeq(blogSeq int) ([]CommentTuple, error) {
	tuples := make([]CommentTuple, 0)

	m1 := "match (blog:Blog)-[:Contain]->(comment:BlogComment)<-[:Publish]-(user:DustUser)"
	c1 := fmt.Sprintf("where blog.seq=%d", blogSeq)
	o1 := "optional match (comment)-[:At]->(atUser:DustUser)"
	r := "return comment, user, atUser order by comment.createTime;"

	cypher := m1 + " " + c1 + " " + o1 + " " + r

	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())
	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return tuples, err
	}

	for (result.Next(context.TODO())) {
		c, _ := result.Record().Get("comment")
		u, _ := result.Record().Get("user")
		a, _ := result.Record().Get("atUser")

		var tuple CommentTuple

		comment := c.(neo4j.Node)
		user := u.(neo4j.Node)

		tuple.CommentNode = &comment
		tuple.PublisherNode = &user

		if a != nil {
			atUser := a.(neo4j.Node)
			tuple.AtNode = &atUser
		}

		tuples = append(tuples, tuple)
	}

	return tuples, nil
}